package Managers;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.LoopMode;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioRenderer;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.Light;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.jme3.util.SkyFactory;
import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import junit.framework.Assert;
import mygame.conf.GameConfiguration;
import mygame.factory.SpatialFactory;
import mygame.model.Game;
import mygame.model.GameLevel;
import mygame.model.GameLight;
import mygame.model.GameNode;
import mygame.model.GameSkyBox;

/**
 * Object Manager to manage all object on the game, also
 * can set level to be loaded by the game. All object
 * are loaded from xml file.
 */
public class ObjectManager {

    private static Node rootNode;
    private static List<AnimChannel> channels = new LinkedList();
    private String[] animNames;
    private static Game game = null;
    private static Boolean isRunning = true;
    private static Node player;
    private static Node first;
    private AudioNode player_walk;
    private AudioNode level1_ambient;
    private float blendTime = 0.5f;
    private static String gameConfPath = null;
    private static GameConfiguration gameConfiguration;
    private static ObjectManager instance;

    int x=0;
    
    public static ObjectManager getInstance() {
        if (instance == null) {
            instance = new ObjectManager();
        }

        return instance;
    }

    private ObjectManager() {
    }

    public static void configure(Game myGame, String conf) {
        ObjectManager.game = myGame;
        ObjectManager.rootNode = myGame.getRootNode();
        gameConfiguration = getInstance().loadGameConfiguration(conf);
    }

    public List<AnimChannel> getChannels() {
        return channels;
    }

    /**
     * Return true if there is no levels to play
     * @param levelNumber
     * @return true if there is no level to play otherwise load levelNumber level
     * into the game.
     */
    public boolean loadLevel(int levelNumber)  {
        
        rootNode.detachAllChildren();
        
        if (gameConfiguration.getLevels().size() == levelNumber) {
            isRunning=false;
            return true;
        }
        
        GameLevel level = gameConfiguration.getLevels().get(levelNumber);

        Assert.assertTrue(Integer.parseInt(level.getName()) == levelNumber);
        GameSkyBox skyBox = level.getSkyBox();
        if( skyBox !=null ){
            Texture envMap;
            envMap = game.getAssetManager().loadTexture(skyBox.getTexture());
            rootNode.attachChild(SkyFactory.createSky(game.getAssetManager(), envMap, new Vector3f(-1, -1, -1), true));
        }
        // adding nodes (Spatials)
        for (GameNode node : level.getNodes()) {
            Spatial child = SpatialFactory.getSpatial(node);
            Assert.assertNotNull(child);
            
             Spatial physicsBox = child;
             RigidBodyControl control = new RigidBodyControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 0);
             physicsBox.addControl(control);
             
             physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(-130+x, 12f, -7));
            
            rootNode.attachChild(child);
            game.getPhysicsSpace().add(child);
            x+=10;
        }
        
        // adding lights
        for (GameLight l: level.getLights()) {
            Light light = SpatialFactory.getLight(l);
            Assert.assertNotNull(light);
            rootNode.addLight(light);
        }
        
               
       //initKeys();

//       AnimControl animControl = rootNorootNde.getChild("Player").getControl(AnimControl.class);
//       Collection<String> pepe=animControl.getAnimationNames();
       
//       for(String s: pepe){
//           System.out.println("ANIMACION: " + s);
//       }
       
//       channels.add(animControl.createChannel());       
//       
//        channels.get(0).setAnim("stand", 50);
//        channels.get(0).setSpeed(7f);
//        channels.get(0).setLoopMode(LoopMode.DontLoop);
        
               
      
        
        
        
       return false;
       
    }

    public void initKeys() {
        // You can map one or several inputs to one named action
        InputManager inputManager = game.getInputManager();

        inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Front", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S));
        
        //inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
        //      new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        
        inputManager.addMapping("walk", new KeyTrigger(KeyInput.KEY_I));
        inputManager.addMapping("punch", new KeyTrigger(KeyInput.KEY_U));
        
        inputManager.addListener(actionListener, new String[]{"Pause"});
        inputManager.addListener(analogListener,
                new String[]{"Left", "Right", "Front", "Back", "walk", "punch"});
    }
    
    private ActionListener actionListener = new ActionListener() {

        @Override
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Pause") && !keyPressed) {
                isRunning = !isRunning;
                game.getMesajeManager().showMesaje("Press P to unpause");
            }
        }
    };
    

    
   
 
    private AnalogListener analogListener = new AnalogListener() {

        @Override
        public void onAnalog(String name, float value, float tpf) {

            if (isRunning) {

                player = (Node) rootNode.getChild("Player");

                AnimChannel channel1 = channels.get(0);
                float speed = 1f;

                if (name.equals("Right")) {
                    Vector3f v = player.getLocalTranslation();
                    player.setLocalTranslation(v.x + value * speed, v.y, v.z);
                    SoundManager.playWalkSound();
                }
                if (name.equals("Left")) {
                    Vector3f v = player.getLocalTranslation();
                    player.setLocalTranslation(v.x - value * speed, v.y, v.z);
                    SoundManager.playWalkSound();
                }
                if (name.equals("Front")) {
                    Vector3f v = player.getLocalTranslation();
                    player.setLocalTranslation(v.x, v.y, v.z - value * speed);
                    SoundManager.playWalkSound();
                }
                if(name.equals("Back")){
                    Vector3f v = player.getLocalTranslation();
                    player.setLocalTranslation(v.x, v.y, v.z + value * speed);
                    // TODO buscar un .wav para caminar hacia atras
                    SoundManager.playWalkSound();
                }

                if(name.equals("punch")) {
                    channel1.setAnim("punch", 50);
                    channel1.setSpeed(20f);
                    channel1.setLoopMode(LoopMode.DontLoop);
                    
                }
                if(name.equals("walk")) {
                    channel1.setAnim("walk", 50);
                    channel1.setSpeed(20f);
                    channel1.setLoopMode(LoopMode.DontLoop);
                    
                }
            } else {
            }

        }
    };

    public AssetManager getAssetManager() {
        return game.getAssetManager();
    }

    public Node getRootNode() {
        return rootNode;
    }

    /**
     * Load game configuration file
     * @param configuration file path
     * @return GameConfiguration instance or null if there is an error.
     */
    private GameConfiguration loadGameConfiguration(String GAME_CONF_FILE) {
        XStream xstream = new XStream();
        xstream.processAnnotations(GameConfiguration.class);
        xstream.useAttributeFor("type", GameNode.TYPE.class);
        GameConfiguration gc = null;
        try {
            gc = (GameConfiguration) xstream.fromXML(new FileInputStream(new File("conf/game.xml")));
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ObjectManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        return gc;
    }

}
